/*!
 * LLM 智能转换核心
 * 
 * 以LLM为中心的C到Rust转换系统，带请求频率控制
 */

use anyhow::{Result, Context};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use tokio::time::sleep;
use rand::Rng;

use crate::config::LlmConfig;
use crate::project_builder::CompileError;

/// LLM响应结构
#[derive(Debug, Deserialize)]
pub struct LlmResponse {
    pub choices: Vec<LlmChoice>,
}

#[derive(Debug, Deserialize)]
pub struct LlmChoice {
    pub message: LlmMessage,
}

#[derive(Debug, Deserialize)]
pub struct LlmMessage {
    pub content: String,
}

/// API频率控制器
#[derive(Debug)]
struct RateLimiter {
    requests: VecDeque<Instant>,
    max_per_5s: u32,
    max_per_day: u32,
}

impl RateLimiter {
    fn new() -> Self {
        Self {
            requests: VecDeque::new(),
            max_per_5s: 15,     // 并发模式下更保守：每5秒最多10次请求
            max_per_day: 2000,  // 每天最多2000次请求
        }
    }
    
    async fn wait_if_needed(&mut self) -> Result<()> {
        let now = Instant::now();
        
        // 并发保护：基础随机延迟 (200-800ms)
        let base_delay = rand::thread_rng().gen_range(200..=400);
        log::debug!("并发保护延迟: {}ms", base_delay);
        sleep(Duration::from_millis(base_delay)).await;
        
        // 清理5秒前的请求记录
        while let Some(&front_time) = self.requests.front() {
            if now.duration_since(front_time) > Duration::from_secs(5) {
                self.requests.pop_front();
            } else {
                break;
            }
        }
        
        // 根据当前请求密度动态调整延迟
        let current_requests = self.requests.len();
        if current_requests > 5 {
            // 高密度请求时增加额外延迟
            let extra_delay = rand::thread_rng().gen_range(1000..=3000);
            log::info!("检测到高频请求 ({} 个)，增加额外延迟: {}ms", current_requests, extra_delay);
            sleep(Duration::from_millis(extra_delay)).await;
        }
        
        // 检查5秒内的请求数量
        if self.requests.len() >= self.max_per_5s as usize {
            let wait_time = Duration::from_secs(5) - now.duration_since(*self.requests.front().unwrap()) 
                + Duration::from_millis(rand::thread_rng().gen_range(500..=1500)); // 添加随机化
            log::warn!("API频率限制，等待 {:.1}秒", wait_time.as_secs_f64());
            sleep(wait_time).await;
        }
        
        // 检查每日请求限制（简化实现，重启后重置）
        if self.requests.len() >= self.max_per_day as usize {
            return Err(anyhow::anyhow!("达到每日请求限制"));
        }
        
        // 记录本次请求
        self.requests.push_back(Instant::now()); // 使用实际发送时间
        Ok(())
    }
}

/// LLM助手 - 转换系统的核心
#[derive(Debug)]
pub struct LlmAssistant {
    client: reqwest::Client,
    config: LlmConfig,
    rate_limiter: Arc<Mutex<RateLimiter>>,
}

impl LlmAssistant {
    pub fn new(config: LlmConfig) -> Result<Self> {
        let client = reqwest::Client::new();
        let rate_limiter = Arc::new(Mutex::new(RateLimiter::new()));
        
        Ok(Self {
            client,
            config,
            rate_limiter,
        })
    }
    
    /// 转换C头文件到Rust导入
    pub async fn convert_header(&self, header: &str) -> Result<Option<String>> {
        let prompt = format!(
            r#"将C头文件转换为Rust导入路径。只返回导入路径，不要任何解释。

C头文件: #include <{}>

如果不需要导入，只返回: SKIP
如果需要导入，只返回导入路径（不含use关键字）

示例:
stdio.h
std::io

stdbool.h  
SKIP

string.h
std::ffi::CString

现在转换: {}"#, header, header
        );
        
        let response = self.call_llm(&prompt).await?;
        let result = self.extract_code(&response)?;
        
        if result.trim() == "SKIP" {
            Ok(None)
        } else {
            Ok(Some(result.trim().to_string()))
        }
    }
    
    /// 转换C函数到Rust函数
    pub async fn convert_function(&self, c_code: &str, context: &str) -> Result<String> {
        // 检查代码大小
        let code_lines = c_code.lines().count();
        let code_chars = c_code.len();
        
        log::info!("转换代码: {} 行, {} 字符", code_lines, code_chars);
        
        if code_lines > 800 {
            log::warn!("⚠️  代码文件较大 ({} 行)，转换可能需要更长时间或失败", code_lines);
            log::warn!("建议: 考虑将大文件拆分成多个小文件后再转换");
        }
        
        let prompt = format!(
            r#"将C代码转换为Rust代码。只输出纯Rust代码，不要任何解释。

上下文: {}

C代码:
```c
{}
```

要求：
1. 生成安全的Rust代码
2. 使用标准库类型替代C类型
3. 适当的错误处理
4. 包含必要的函数和结构体

只返回Rust代码："#, 
            context, c_code
        );
        
        let response = self.call_llm(&prompt).await?;
        self.extract_code(&response)
    }
    
    /// 分析C代码结构（带重试机制）
    pub async fn analyze_c_file(&self, c_content: &str) -> Result<FileAnalysis> {
        const MAX_RETRIES: u32 = 3;
        const RETRY_DELAY_SECS: u64 = 10; // 分析重试间隔较短
        
        let prompt = format!(
            r#"分析以下C代码，返回JSON格式结果。

```c
{}
```

要求：返回格式严格为JSON，不要任何其他文字。

示例格式：
{{"functions":["main","add"],"includes":["stdio.h"],"global_vars":["count"],"main_purpose":"简短描述"}}

重要：
1. 必须是完整有效的JSON
2. 所有字段都必须存在  
3. 数组可以为空但不能省略
4. 描述保持简短（少于50字符）

现在分析上述C代码并返回JSON："#, 
            c_content
        );
        
        for attempt in 1..=MAX_RETRIES {
            match self.call_llm(&prompt).await {
                Ok(response) => {
                    // 先记录原始API响应用于调试
                    log::info!("=== LLM原始响应 (尝试 {}) ===", attempt);
                    if let Some(first_choice) = response.choices.first() {
                        log::info!("完整响应内容: {}", first_choice.message.content);
                        log::info!("响应长度: {} 字符", first_choice.message.content.len());
                    }
                    log::info!("=== 原始响应结束 ===");
                    
                    match self.extract_code(&response) {
                        Ok(json_str) => {
                            log::info!("提取后的JSON内容: {}", json_str);
                            log::info!("提取后长度: {} 字符", json_str.len());
                            
                            // 尝试解析JSON
                            match serde_json::from_str::<FileAnalysis>(&json_str) {
                                Ok(analysis) => return Ok(analysis),
                                Err(e) => {
                                    if attempt < MAX_RETRIES {
                                        log::warn!("文件分析JSON解析失败 (尝试 {}/{}): {}，重试...", 
                                                  attempt, MAX_RETRIES, e);
                                        log::error!("===== JSON解析错误详情 =====");
                                        log::error!("错误: {}", e);
                                        log::error!("JSON内容: '{}'", json_str);
                                        log::error!("JSON长度: {}", json_str.len());
                                        if json_str.is_empty() {
                                            log::error!("JSON内容为空！");
                                        }
                                        log::error!("===========================");
                                        sleep(Duration::from_secs(RETRY_DELAY_SECS)).await;
                                        continue;
                                    } else {
                                        return Err(anyhow::anyhow!(
                                            "JSON解析失败，已达到最大重试次数: {}\n响应内容: '{}'", 
                                            e, json_str
                                        ));
                                    }
                                }
                            }
                        }
                        Err(e) => {
                            if attempt < MAX_RETRIES {
                                log::warn!("提取分析内容失败 (尝试 {}/{}): {}，重试...", 
                                          attempt, MAX_RETRIES, e);
                                sleep(Duration::from_secs(RETRY_DELAY_SECS)).await;
                                continue;
                            } else {
                                return Err(e);
                            }
                        }
                    }
                }
                Err(e) => {
                    if attempt < MAX_RETRIES {
                        log::warn!("LLM分析调用失败 (尝试 {}/{}): {}，重试...", 
                                  attempt, MAX_RETRIES, e);
                        sleep(Duration::from_secs(RETRY_DELAY_SECS)).await;
                        continue;
                    } else {
                        return Err(e);
                    }
                }
            }
        }
        
        Err(anyhow::anyhow!("文件分析重试逻辑异常"))
    }
    
    /// 调用LLM API（带重试机制）
    async fn call_llm(&self, prompt: &str) -> Result<LlmResponse> {
        const MAX_RETRIES: u32 = 3;
        const RETRY_DELAY_SECS: u64 = 30;
        
        for attempt in 1..=MAX_RETRIES {
            // 频率控制
            {
                let mut limiter = self.rate_limiter.lock().unwrap();
                limiter.wait_if_needed().await?;
            }
            
            let request_body = serde_json::json!({
                "model": self.config.model,
                "messages": [
                    {
                        "role": "user",
                        "content": prompt
                    }
                ],
                "temperature": 0.1,  // 降低随机性，提高JSON格式一致性
                "max_tokens": self.config.max_tokens.unwrap_or(16000),
            });
            
            let response = self.client
                .post(&self.config.endpoint)
                .header("Authorization", format!("Bearer {}", 
                    self.config.api_key.as_ref().unwrap_or(&"".to_string())))
                .header("Content-Type", "application/json")
                .json(&request_body)
                .timeout(Duration::from_secs(self.config.timeout_seconds))
                .send()
                .await
                .with_context(|| format!("LLM API调用失败 (尝试 {}/{})", attempt, MAX_RETRIES))?;
            
            let status = response.status();
            log::debug!("HTTP 状态码: {}", status);
            
            let response_text = response.text().await
                .with_context(|| "获取响应文本失败")?;
            
            log::debug!("LLM API 响应长度: {} 字符", response_text.len());
            if !status.is_success() {
                log::error!("API 错误响应 (状态 {}): {}", status, 
                           &response_text[..response_text.len().min(500)]);
            }
            
            // 检查是否是请求限制错误
            if response_text.contains("Request limit exceeded") {
                if attempt < MAX_RETRIES {
                    log::warn!("遇到API请求限制 (尝试 {}/{}），等待{}秒后重试...", 
                              attempt, MAX_RETRIES, RETRY_DELAY_SECS);
                    sleep(Duration::from_secs(RETRY_DELAY_SECS)).await;
                    continue;
                } else {
                    return Err(anyhow::anyhow!(
                        "API请求限制：已达到最大重试次数 ({})，请稍后再试或检查API配额",
                        MAX_RETRIES
                    ));
                }
            }
            
            // 尝试解析响应
            match serde_json::from_str(&response_text) {
                Ok(parsed_response) => return Ok(parsed_response),
                Err(e) => {
                    if attempt < MAX_RETRIES {
                        log::warn!("解析响应失败 (尝试 {}/{}): {}，等待{}秒后重试...", 
                                  attempt, MAX_RETRIES, e, RETRY_DELAY_SECS);
                        sleep(Duration::from_secs(RETRY_DELAY_SECS)).await;
                        continue;
                    } else {
                        return Err(anyhow::anyhow!(
                            "解析LLM响应失败，已达到最大重试次数: {}\n响应内容: {}", 
                            e, response_text
                        ));
                    }
                }
            }
        }
        
        // 理论上不会执行到这里
        Err(anyhow::anyhow!("API调用重试逻辑异常"))
    }
    
    /// 提取代码块或纯文本
    fn extract_code(&self, response: &LlmResponse) -> Result<String> {
        let content = response.choices.first()
            .ok_or_else(|| anyhow::anyhow!("LLM响应为空"))?
            .message.content.clone();
        
        let trimmed_content = content.trim();
        
        log::debug!("===== extract_code 调试信息 =====");
        log::debug!("原始内容长度: {}", content.len());
        log::debug!("去除空白后长度: {}", trimmed_content.len());
        log::debug!("内容开头: '{}'", &trimmed_content.chars().take(50).collect::<String>());
        log::debug!("内容结尾: '{}'", &trimmed_content.chars().rev().take(50).collect::<String>().chars().rev().collect::<String>());
        log::debug!("行数: {}", content.lines().count());
        log::debug!("=====================================");
        
        // 首先检查是否有代码块
        if let Some(start) = content.find("```") {
            log::debug!("发现代码块标记，提取代码块内容");
            let code_start = if content[start..].starts_with("```rust") {
                start + 7
            } else if content[start..].starts_with("```json") {
                start + 7
            } else {
                start + 3
            };
            
            if let Some(end_relative) = content[code_start..].find("```") {
                let code_end = code_start + end_relative;
                return Ok(content[code_start..code_end].trim().to_string());
            }
        }
        
        // 检查是否为完整JSON（以{开头，以}结尾）
        if trimmed_content.starts_with('{') && trimmed_content.ends_with('}') {
            log::debug!("检测到完整JSON格式，直接返回");
            return Ok(trimmed_content.to_string());
        }
        
        // 检查是否为数组JSON（以[开头，以]结尾）
        if trimmed_content.starts_with('[') && trimmed_content.ends_with(']') {
            log::debug!("检测到JSON数组格式，直接返回");
            return Ok(trimmed_content.to_string());
        }
        
        // 对于简短的单行回答（如导入语句），查找最短的有意义行
        let lines: Vec<&str> = content.lines().collect();
        log::debug!("内容行数: {}，是否应用最短行逻辑: {}", lines.len(), lines.len() <= 3);
        
        if lines.len() <= 3 {  // 只有少量行时才使用最短行逻辑
            let mut shortest_line = "";
            let mut min_length = usize::MAX;
            
            for (i, line) in lines.iter().enumerate() {
                let trimmed = line.trim();
                log::debug!("检查行 {}: '{}' (长度: {})", i, trimmed, trimmed.len());
                
                if !trimmed.is_empty() 
                    && !trimmed.starts_with("C头文件") 
                    && !trimmed.starts_with("如果")
                    && !trimmed.starts_with("现在")
                    && !trimmed.contains("示例")
                    && !trimmed.contains("：")
                    && !trimmed.contains("。")
                    && trimmed.len() < min_length {
                    min_length = trimmed.len();
                    shortest_line = trimmed;
                    log::debug!("更新最短行: '{}' (长度: {})", shortest_line, min_length);
                }
            }
            
            if !shortest_line.is_empty() {
                log::debug!("返回最短行: '{}'", shortest_line);
                return Ok(shortest_line.to_string());
            }
        }
        
        // 默认返回完整内容（去除前后空白）
        log::debug!("未识别特定格式，返回完整内容");
        Ok(trimmed_content.to_string())
    }
    
    /// 基于编译错误修复代码
    pub async fn fix_compile_errors(&self, original_code: &str, errors: &[CompileError], file_name: &str) -> Result<String> {
        const MAX_FIX_RETRIES: u32 = 2;
        const FIX_DELAY_SECS: u64 = 10;
        
        // 构建错误信息摘要
        let error_summary = errors.iter()
            .map(|e| {
                let mut summary = format!("错误: {}\n位置: {} 行{}\n", 
                    e.message, 
                    e.file,
                    if let Some(line) = e.line_number { 
                        format!(" {}", line) 
                    } else { 
                        String::new() 
                    }
                );
                
                // 添加详细信息
                if !e.details.is_empty() {
                    summary.push_str("详细信息:\n");
                    for detail in &e.details {
                        summary.push_str(&format!("  {}\n", detail));
                    }
                }
                
                summary
            })
            .collect::<Vec<_>>()
            .join("\n");
        
        let prompt = format!(
            r#"以下Rust代码存在编译错误，请修复它们：

文件名: {}

当前代码:
```rust
{}
```

编译错误:
{}

要求：
1. 修复所有编译错误
2. 保持代码的原始逻辑和功能
3. 使用安全的Rust习惯
4. 只返回修复后的完整代码，不要解释

修复后的代码："#, 
            file_name, original_code, error_summary
        );
        
        log::info!("===== 发送给LLM的修复Prompt =====");
        log::info!("{}", prompt);
        log::info!("=================================");
        
        for attempt in 1..=MAX_FIX_RETRIES {
            match self.call_llm(&prompt).await {
                Ok(response) => {
                    match self.extract_code(&response) {
                        Ok(fixed_code) => {
                            log::info!("代码修复完成 (尝试 {}): {} -> {} 字符", 
                                      attempt, original_code.len(), fixed_code.len());
                            return Ok(fixed_code);
                        }
                        Err(e) => {
                            if attempt < MAX_FIX_RETRIES {
                                log::warn!("提取修复代码失败 (尝试 {}/{}): {}，重试...", 
                                          attempt, MAX_FIX_RETRIES, e);
                                sleep(Duration::from_secs(FIX_DELAY_SECS)).await;
                                continue;
                            } else {
                                return Err(e);
                            }
                        }
                    }
                }
                Err(e) => {
                    if attempt < MAX_FIX_RETRIES {
                        log::warn!("代码修复调用失败 (尝试 {}/{}): {}，重试...", 
                                  attempt, MAX_FIX_RETRIES, e);
                        sleep(Duration::from_secs(FIX_DELAY_SECS)).await;
                        continue;
                    } else {
                        return Err(e);
                    }
                }
            }
        }
        
        Err(anyhow::anyhow!("代码修复重试逻辑异常"))
    }
}

/// 文件分析结果
#[derive(Debug, Serialize, Deserialize)]
pub struct FileAnalysis {
    pub functions: Vec<String>,
    pub includes: Vec<String>,
    pub global_vars: Vec<String>,
    pub main_purpose: String,
}